package com.scalar.chiptrack.workflow;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.jgraph.graph.DefaultEdge;
import com.jgraph.graph.DefaultGraphCell;
import com.jgraph.graph.DefaultGraphModel;
import com.jgraph.graph.DefaultPort;
import com.jgraph.graph.Edge;

// A Custom Model that does not allow Self-References
public class WorkflowModel extends DefaultGraphModel {
	
	protected Editor editor;
	// Override Superclass Method
	public boolean acceptsSource(Object edge, Object port) {
		// Source only Valid if not Equal Target
		return (((Edge) edge).getTarget() != port);
	}
	
	// Override Superclass Method
	public boolean acceptsTarget(Object edge, Object port) {
		// Target only Valid if not Equal Source
		return (((Edge) edge).getSource() != port);
	}
	
	public void setEditor(Editor editor){
		this.editor = editor;
	}
	
	public Editor getEditor(){
		return editor;
	}
	
	public String displayCells(){
		
		StringBuffer sb = new StringBuffer();
		int count = getRootCount();
		ArrayList cellList = new ArrayList();
		ArrayList edgeList = new ArrayList();
				
		for(int i = 0; i<count; i++){
			Object cell = getRootAt(i);
			if(cell instanceof DefaultGraphCell){
				if (cell instanceof DefaultEdge){
					edgeList.add(cell);			
				}else{
					cellList.add(cell);
				}
			}
		}
		
		Iterator it =cellList.iterator();
		while(it.hasNext()){
			Object temp = it.next();
			sb.append("Cell = "+temp+"\n");
			sb.append("Attributes = " + ((DefaultGraphCell)temp).getAttributes()+"\n");
			Set edges = getOutgoingTransitions(temp);
			
			if(edges.isEmpty()){
				edges = getIncomingTransitions(temp);
				sb.append("In Edges = "+edges+"\n");
			}else{
				sb.append("Out Edges = "+edges+"\n");
			}
			sb.append("\n");
		}
		
		return sb.toString();
	}
	
	public ArrayList getAllCells(){
		
		int count = getRootCount();
		ArrayList cellList = new ArrayList();		
		for(int i = 0; i<count; i++){
			Object cell = getRootAt(i);
			if(cell instanceof DefaultGraphCell){
				if (cell instanceof DefaultEdge){
				}else{
					cellList.add(cell);
				}
			}
		}
		
		return cellList;
	}
	
	public ArrayList getAllEdges(){
		
		int count = getRootCount();
		ArrayList edgeList = new ArrayList();
				
		for(int i = 0; i<count; i++){
			Object cell = getRootAt(i);
			if(cell instanceof DefaultGraphCell){
				if (cell instanceof DefaultEdge){
					//System.out.println("Edge Attr = "+((DefaultEdge)cell).getAttributes());
					edgeList.add(cell);
				}else{
					
				}
			}
		}
		
		/*ArrayList list = getAllCells();
		Iterator it = list.iterator();
		
		while(it.hasNext())
		{
			edgeList.addAll( getOutgoingTransitions( it.next() ) );
		}
		
		System.out.println("  edgeList size   "+ edgeList.size());
		*/
		return edgeList;
	}
	
	public Object getFirstCell(){
		return getRootAt(0);
	}
	
	public DefaultGraphCell getCell(String fromId){
		
		ArrayList returnList = new ArrayList();
		ArrayList list = getAllCells();
		
		Iterator it = list.iterator();
		
		while(it.hasNext()){
			
			DefaultGraphCell cell = (DefaultGraphCell)it.next();		
			Map map = cell.getAttributes();
			String id = (String)map.get("attrId");
			
			if((id != null) && id.equalsIgnoreCase(fromId)){
				return cell;
			}
		}
		
		return null;
	}
	
	public DefaultPort getPort(Object cell){
		List list = ((DefaultGraphCell)cell).getChildren();
		for(Iterator it =list.iterator() ; it.hasNext();){
			Object child = it.next();
			if(child instanceof DefaultPort){
				return (DefaultPort)child; 
			}
		}
		
		return null;
	}
	
	public Set getIncomingTransitions(Object cell){
		Set incomingTransitions = new HashSet();
		for(Iterator it = getPort(cell).edges(); it.hasNext();){
			DefaultEdge edge = (DefaultEdge)it.next();
			Object target = ((DefaultPort)(edge.getTarget())).getParent();
			
			if(cell == target){
				incomingTransitions.add(edge);
			}
		}
		return incomingTransitions;
	}
	
	public Set getOutgoingTransitions(Object cell){
		
		Set outputTransitions=new HashSet();
		if(!editor.isGroup(cell)){
      		for( Iterator i = getPort(cell).edges(); i.hasNext();){
         		DefaultEdge edge = (DefaultEdge)i.next();
         		Object source = ((DefaultPort)(edge.getSource())).getParent();
         		if(cell==source) {
            		outputTransitions.add(edge);
         		}
      		}
      	}
      	
      	return outputTransitions;
	}
	

}